﻿using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using SharpDX;
using SharpDX.XAPO;
using SynergyLib.DSP;
using SynergyLib.SMath;

namespace XAudio2Controls
{
    [StructLayout(LayoutKind.Sequential)]
    public struct FlangerParams
    {
        internal float DelayMS { get; set; }
        internal float Feedback { get; set; }
        internal float Rate { get; set; }
    }
    /// <summary>
    /// A Flanger effect
    /// </summary>
    public class FlangerEffect : AudioProcessorBase<FlangerParams>
    {
        #region Properties
        private float max_time_delay
        {
            get { return Parameters.DelayMS; }
        }
        private float amp
        {
            get { return Parameters.Feedback; }
        }
        #endregion Properties

        public override void Process(BufferParameters[] inputProcessParameters, BufferParameters[] outputProcessParameters, bool isEnabled)
        {
            int frameCount = inputProcessParameters[0].ValidFrameCount;
            DataStream input = new DataStream(inputProcessParameters[0].Buffer, frameCount * InputFormatLocked.BlockAlign, true, true);
            DataStream Output = new DataStream(inputProcessParameters[0].Buffer, frameCount * InputFormatLocked.BlockAlign, true, true);
            for (int i = 0; i < frameCount; i++, Counter++)
            {
                float left = input.Read<float>();
                float right = input.Read<float>();
                Output.Write((float)((left * amp) + amp * (left - cur_delay(Counter))));
                Output.Write((float)((right * amp) + amp * (right - cur_delay(Counter))));
                #region old code

                /*
                 * 
                double l_Delay = DelayBasedEffects.Delay(left, Parameters.DelayMS, Counter, Parameters.Rate, InputFormatLocked.SampleRate);
                   
                     * (
                    (left) +
                    ((1 - (Parameters.DelayMS)) * (Math.Sin(Trig.TwoPI * Counter * ((Parameters.Rate) / InputFormatLocked.SampleRate))
                   
                    ))
                    );
               
                double r_Delay = (
                    (right) +
                    ((1 - (Parameters.DelayMS)) * (Math.Sin(Trig.TwoPI * Counter* ((Parameters.Rate) / InputFormatLocked.SampleRate))
                    
                    ))
                    );
                 * 
                    */

                /*
                float l_outputSignal = (float)DelayBasedEffects.Delay(left, Parameters.DelayMS, Counter, Parameters.Rate, InputFormatLocked.SampleRate) * left;
                float r_outputSignal = (float)DelayBasedEffects.Delay(right, Parameters.DelayMS, Counter, Parameters.Rate, InputFormatLocked.SampleRate) * right;

                double l_feedback = (Parameters.Feedback) * (l_outputSignal);
                double r_feedback = (Parameters.Feedback) * (r_outputSignal);                

                Output.Write(l_outputSignal + (float)l_feedback);
                Output.Write(r_outputSignal + (float)r_feedback);
                */
                #endregion oldcode
            }
        }
        #region Private Methods
        /// <summary>
        /// Sine reference to create oscillating delay
        /// </summary>
        private float sin_ref(int index)
        {
            return (float)Math.Sin(Trig.TwoPI * index * (Parameters.Rate / InputFormatLocked.SampleRate));
        }
        private float cur_sin(int index)
        {
            return Math.Abs(sin_ref(index));
        }
        /// <summary>
        /// generate delay from 1 - max_samp_delay and ensure whole number
        /// </summary>
        /// <returns></returns>
        private float cur_delay(int index)
        {
            return (float)(cur_sin(index) * (1 - max_time_delay));
        }
        #endregion Private Methods
    }
}